package com.snail.common.excel.handler;

import com.alibaba.excel.converters.AutoConverter;
import com.alibaba.excel.converters.Converter;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.metadata.data.WriteCellData;
import com.alibaba.excel.write.handler.CellWriteHandler;
import com.alibaba.excel.write.handler.context.CellWriteHandlerContext;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteTableHolder;
import com.snail.common.core.enums.BizStatus;
import com.snail.common.excel.annotation.Excel;
import com.snail.common.excel.annotation.ExcelContentMerge;
import com.snail.common.excel.annotation.ExcelDataValidation;
import com.snail.common.excel.constants.ExcelConstants;
import lombok.SneakyThrows;
import org.apache.poi.hssf.usermodel.HSSFDataValidation;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.ss.util.CellRangeAddressList;

import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @Description: 单元格写入Handler
 * @Author: Snail
 * @CreateDate: 2023/8/17 17:24
 * @Version: V1.0
 */
public class SnailCellWriteHandler implements CellWriteHandler {

    @Override
    public void beforeCellCreate(CellWriteHandlerContext context) {
        Class<?> clazz = context.getWriteSheetHolder().getClazz();
        if (clazz == null) {
            return;
        }
        Head headData = context.getHeadData();
        if (headData == null) {
            return;
        }
        String fieldName = headData.getFieldName();
        Converter<?> converter = getFieldConverter(clazz, fieldName);
        if (converter == null) {
            return;
        }
        context.getExcelContentProperty().setConverter(converter);
    }

    @SneakyThrows
    private Converter<?> getFieldConverter(Class<?> clazz, String fieldName) {
        Converter<?> converter = null;
        //属性
        Field[] fields = clazz.getDeclaredFields();
        //获取
        for (Field field : fields) {
            if (!field.getName().equalsIgnoreCase(fieldName)) {
                continue;
            }
            Excel excel = field.getAnnotation(Excel.class);
            //没有Excel注解
            if (excel == null) {
                continue;
            }
            Class<? extends Converter<?>> convertClazz = excel.converter();
            if (convertClazz == null) {
                continue;
            }
            if (convertClazz == AutoConverter.class) {
                continue;
            }
            if (!fieldName.equals(field.getName())) {
                continue;
            }
            converter = convertClazz.getDeclaredConstructor().newInstance();
        }
        if (converter != null) {
            return converter;
        }
        //父类
        Class<?> superclass = clazz.getSuperclass();
        if (superclass != null) {
            converter = getFieldConverter(superclass, fieldName);
        }
        return converter;
    }

    @SneakyThrows
    @Override
    public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List<WriteCellData<?>> cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {
        //当前行
        int curRowIndex = cell.getRowIndex();
        //当前列
        int curColIndex = cell.getColumnIndex();
        int headRowNumber = writeSheetHolder.getExcelWriteHeadProperty().getHeadRowNumber();
        if(curRowIndex + 1 == headRowNumber){
            dataValidation(writeSheetHolder,head, curRowIndex, curColIndex);
        }
        // 如果当前行小于了表头的行数
        if (curRowIndex < headRowNumber + 1) {
            return;
        }
        // 当前单元格是否合并
        if (isMerge(head)) {
            // 合并单元格
            mergeCell(writeSheetHolder, cell, head, curRowIndex, curColIndex);
        }
    }

    /**
     * 设置数据选项
     *
     * @param writeSheetHolder writeSheetHolder
     * @param head             头信息
     * @param curRowIndex      当前行
     * @param curColIndex      当前列
     */
    private void dataValidation(WriteSheetHolder writeSheetHolder, Head head, int curRowIndex, int curColIndex) throws Exception {
        Field field = head.getField();
        ExcelDataValidation excelDataValidation = field.getAnnotation(ExcelDataValidation.class);
        if(excelDataValidation == null){
            return;
        }
        Sheet sheet = writeSheetHolder.getSheet();
        DataValidationHelper helper = sheet.getDataValidationHelper();
        DataValidationConstraint validationConstraint = helper.createExplicitListConstraint(excelDataValidation.value());
        CellRangeAddressList rangeAddressList = new CellRangeAddressList(curRowIndex,1000,curColIndex,curColIndex);
        DataValidation dataValidation = helper.createValidation(validationConstraint,rangeAddressList);
        dataValidation.createErrorBox("错误",excelDataValidation.msg());
        dataValidation.setShowErrorBox(true);
        sheet.addValidationData(dataValidation);
    }

    /**
     * 合并单元格
     *
     * @param writeSheetHolder writeSheetHolder
     * @param cell             单元格
     * @param head             头信息
     * @param curRowIndex      当前行
     * @param curColIndex      当前列
     */
    private void mergeCell(WriteSheetHolder writeSheetHolder, Cell cell, Head head, int curRowIndex, int curColIndex) throws Exception {
        Sheet sheet = writeSheetHolder.getSheet();
        // 获取当前单元格数据
        String cellValue = cell.getStringCellValue();
        String preCellValue = cell.getSheet().getRow(curRowIndex - 1).getCell(curColIndex).getStringCellValue();

        if (!cellValue.equalsIgnoreCase(preCellValue)) {
            return;
        }
        List<CellRangeAddress> mergedRegions = sheet.getMergedRegions();
        boolean isMerged = false;
        // 判断前一个列是否合并
        boolean isPreMerged = true;
        if (isPreMerged(head)) {
            isPreMerged = mergedRegions.stream().anyMatch(item -> curColIndex == 0 || item.isInRange(curRowIndex, curColIndex - 1));
        }
        for (int j = 0; j < mergedRegions.size(); j++) {
            CellRangeAddress cellAddresses = mergedRegions.get(j);
            if (!cellAddresses.isInRange(curRowIndex - 1, curColIndex) || !isPreMerged) {
                continue;
            }
            sheet.removeMergedRegion(j);
            cellAddresses.setLastRow(curRowIndex);
            sheet.addMergedRegion(cellAddresses);
            isMerged = true;
        }
        if (!isMerged && isPreMerged) {
            sheet.addMergedRegion(new CellRangeAddress(curRowIndex - 1, curRowIndex, curColIndex, curColIndex));
        }
    }

    /**
     * 是否合并单元格
     *
     * @param head 头信息
     * @return 结果
     */
    private boolean isMerge(Head head) throws Exception {
        Field field = head.getField();
        if (field == null) {
            return false;
        }
        return field.getAnnotation(ExcelContentMerge.class) != null;
    }


    /**
     * 是否合并单元格
     *
     * @param head 头信息
     * @return 结果
     */
    private boolean isPreMerged(Head head) throws Exception {
        Field field = head.getField();
        if (field == null) {
            return false;
        }
        ExcelContentMerge annotation = field.getAnnotation(ExcelContentMerge.class);
        if (annotation == null) {
            return false;
        }
        return ExcelConstants.MERGE_SAME_CONTENT_PRE.equals(annotation.mergeStrategy());
    }
}
